package com.kalua.list.harvester.execution;

import static com.kalua.list.harvester.ContentUtil.getContent;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.Executor;

import org.apache.commons.lang.StringUtils;
import org.apache.http.client.ClientProtocolException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.kalua.list.harvester.crawldata.History;
import com.kalua.list.harvester.parser.ContentLinkExtractor;

public class CrawlTask implements Runnable {

	private static final Logger logger = LoggerFactory.getLogger(CrawlTask.class);
	
	private int depth;
	private String targetUrl;
	private int connectTimeout;
	private Executor executor;
	private ContentLinkExtractor linkExtractor;
	private History history;
	
	public CrawlTask(	int depth,
									String targetUrl,
									int connectTimeout,
									Executor executor,
									ContentLinkExtractor linkExtractor,
									History history) {
		this.depth = depth;
		this.targetUrl = targetUrl;
		this.connectTimeout = connectTimeout;
		this.executor = executor;
		this.linkExtractor = linkExtractor;
		this.history = history;
	}
	
	@Override
	public void run() {
		try {
			String content = getContent(	this.targetUrl, 	
														this.connectTimeout);
				
			if (!StringUtils.isEmpty(content)) {				
				this.linkExtractor.compile(content);
				this.history.saveProductPages(	linkExtractor.getMetaSearchInfo(),
																linkExtractor.getProductLinks());				
				Set<String> linksToFollow = linkExtractor.getLinksToFollow();
				CrawlTask child;
				for (String toFollow : linksToFollow) {
					child = spawnChildTask(toFollow);
					if (child!=null) executor.execute(child);
				}				
			}else  logger.warn("Empty Content returned by url {}.", this.targetUrl);			
		} catch (ClientProtocolException exce) {
			logger.error("Invalid Protocol specified in url {}.", this.targetUrl, exce);
		} catch (IOException exce) {
			logger.error("Possible timeout following  url {} at depth {}.", this.targetUrl, this.depth,exce);
		} catch (Throwable exce) {
			logger.error("Unexpected exception following  url {} at depth {}.", this.targetUrl, this.depth,exce);
		}
	}

	private CrawlTask spawnChildTask(String toFollow) {
		CrawlTask result;		
		if (this.history.registerLink(toFollow)) {
			result = new CrawlTask(	this.depth+1, toFollow, 
													this.connectTimeout, 
													this.executor, 
													this.linkExtractor.fromPrototype(), 
													this.history);
			logger.debug("Spawning child task for URL {}.", toFollow);
		} else {
			result = null;
			logger.debug("Ignoring {} as it has already been visited.", toFollow);			
		}		
		return result;
	}
}